import logging
import uuid
from contextvars import ContextVar
import os
import sys
from pathlib import Path

from loguru import logger

from app.core.config import settings


# loguru 替换 log ttps://zhuanlan.zhihu.com/p/15448544324
class InterceptHandler(logging.Handler):
    """
    日志拦截处理器：将所有 Python 标准日志重定向到 Loguru （用于处理uvicorn / fastapi 等自带的日志）

    工作原理：
    1. 继承自 logging.Handler
    2. 重写 emit 方法处理日志记录
    3. 将标准库日志转换为 Loguru 格式
    """

    def emit(self, record: logging.LogRecord) -> None:
        # 尝试获取日志级别名称
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno
        # 获取调用帧信息
        frame, depth = logging.currentframe(), 2
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        # 使用 Loguru 记录日志
        logger.opt(depth=depth, exception=record.exc_info).log(
            level,
            record.getMessage()
        )

# 使用任务request_id来实现全链路日志追踪
_x_request_id: ContextVar[str] = ContextVar('x_request_id', default="")  # 请求ID
_trace_id: ContextVar[str] = ContextVar('x_trace_id', default="")           # 任务ID

class TraceID:
    """全链路追踪ID"""
    
    @staticmethod
    def set(req_id: str) -> ContextVar[str]:
        """设置请求ID，外部需要的时候，可以调用该方法设置
        Returns:
            ContextVar[str]: _description_
        """
        if not req_id:
            req_id = uuid.uuid4().hex
        _x_request_id.set(req_id)
        return _x_request_id

    @staticmethod
    def set_trace(id: str, title: str = "task") -> ContextVar[str]:
        """设置全链路追踪ID
        Returns:
            ContextVar[str]: _description_
        """
        id = f"{title}:{id}"
        _trace_id.set(id)
        return _trace_id
    
def _logger_filter(record):
    record['request_id'] = f"{_x_request_id.get()}"
    return True

# def _logger_filter(record):
#     record['trace_msg'] = f"{_x_request_id.get()} | {_trace_id.get()}"
#     return record['trace_msg']

def setup_logging():
    """
    配置日志系统

    功能：
    1. 控制台彩色输出
    2. 文件日志轮转
    3. 错误日志单独存储
    4. 异步日志记录
    """
    # 步骤1：移除默认处理器
    # logger.configure(extra={"request_id": ''})  # Default values 否则会报错
    logger.remove()

    # 步骤2：定义日志格式
    log_format = (
        # 时间信息 + UUID
        "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | {request_id} | "
        # "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | {extra[request_id]} | "
        # "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
        # "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> {correlation_id} | "
        # 日志级别，居中对齐
        "<level>{level: ^8}</level> | "
        # 进程和线程信息
        "process [<cyan>{process}</cyan>]:<cyan>{thread}</cyan> | "
        # 文件、函数和行号
        "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
        # 日志消息
        "<level>{message}</level>"
    )

    # 步骤3：配置控制台输出
    # logger.add(
    #     sys.stdout,
    #     format=log_format,
    #     level="DEBUG" if settings.DEBUG else "INFO",
    #     # enqueue=True,  # 启用异步写入
    #     backtrace=False,  # 显示完整的异常回溯
    #     # diagnose=True,  # 显示变量值等诊断信息
    #     # colorize=True,  # 启用彩色输出
    #     # filter=correlation_id_filter

    # )

    # 步骤4：创建日志目录
    log_dir = Path(settings.LOG_DIR, "logs")
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)

    # 步骤5：配置常规日志文件
    logger.add(
        str(Path(log_dir, "log.log")),
        format=log_format,
        level="INFO",
        rotation="10 MB",
        retention="7 days",
        encoding="utf-8",
        enqueue=True,  # 异步写入
        filter=_logger_filter,
        # filter=correlation_id_filter

    )

    # 步骤6：配置错误日志文件
    logger.add(
        str(Path(log_dir, "error.log")),
        format=log_format,
        level="ERROR",
        rotation="10 MB",
        retention="1 week",
        encoding="utf-8",
        enqueue=True,  # 异步写入
        # filter=correlation_id_filter
    )

    # 增加控制台输出
    logger.add(
        sys.stdout,
        format=log_format,
        level="INFO",
    )
    # 步骤7：配置 标准库日志 / 第三方库日志
    # logging.getLogger('sqlalchemy.engine').setLevel(logging.WARNING)
    logger_name_list = [name for name in logging.root.manager.loggerDict]
    for logger_name in logger_name_list:
        # print(logger_name)
        _logger = logging.getLogger(logger_name)
        if logger_name.startswith('sqlalchemyxx'):
            _logger.setLevel(logging.WARNING)
        else:
            _logger.setLevel(logging.INFO)
        _logger.handlers = []
        if '.' not in logger_name:
            _logger.addHandler(InterceptHandler())
